package com.dhy.chat;

import com.dhy.msg.Message;
import com.dhy.msg.MessageUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.List;

@ServerEndpoint(value = "/chat/{uname}",configurator = GetHttpSessionConfigurator.class)//指定请求路径
@Component
public class chatEndPoint
{
    //用来存储每一个客户端对象对应的ChatEndPoint对象
    //所有用户共享一个map集合
    private static Map<String,chatEndPoint> onlineUsers=new ConcurrentHashMap<>();

    //线程安全的静态变量，表示在线连接数
    private static volatile  int onlineNum=0;

    //声明session对象，通过该对象可以发送消息给指定的用户
    //每一个用户都有一个自己的session对象
    private  Session session;

    //当前登录的用户名
    private String uname;

    //jackSon使用
    ObjectMapper objectMapper=new ObjectMapper();

    @OnOpen//连接建立时被调用
    public void OnOpen(@PathParam("uname")String uname, Session session, EndpointConfig config) throws IOException
    {
        //判断session是否开启，没有开启使用session发送信息，会报错
        if(!session.isOpen())
        {
            System.out.println("当前session处于关闭状态");
            return;
        }
        System.out.println("连接建立");

        //将局部的sesssion对象赋值给成员session
        this.session=session;
        this.uname=uname;
        //将当前对象存储到容器中
        onlineUsers.put(uname,this);
        //在线人数
        onlineNum++;
        System.out.println("===================");
        System.out.println("当前在线人数:"+onlineNum);
        System.out.println("当前登录的用户:"+uname);
        System.out.println("=========================");
        System.out.println("打印在线的所有用户:");
        for (Map.Entry<String, chatEndPoint> entry : onlineUsers.entrySet()) {
            System.out.println(entry.getKey());
        }
        //将当前用户在线的情况推送给所有的客户端,自己除外
        //1.获取消息
        String message = MessageUtils.getMessage(true, null, onlineUsers.keySet());
        //2.调用方法进行系统消息的推送
        List<String> onlineFriends = broadcatAllUsers(message, uname);
        //3.发送消息给客户端，展示当前在线的好友
       // displayOnlineFriends(onlineFriends,uname);
    }

    //广播告诉其他人自己上线了
    private List<String> broadcatAllUsers(String message,String curUserName)
    {
        if(!session.isOpen())
        {
            System.out.println("广播失败,当前session处于关闭状态");
            return null;
        }
        List<String> onlineFriends=new ArrayList<>();
        try{
            //要将该消息推送给所有的客户端
            Set<String> names = onlineUsers.keySet();
            for (String name : names) {
                //不可能自己上线了，还要通知自己一声吧
                if(curUserName.equals(name))
                {
                    System.out.println("不通知自己:"+name);
                    continue;
                }
                System.out.println("当前通知的用户:"+name);
                onlineFriends.add(name);
                //获取每一个用户的chatEndPoint对象,然后向每一个客户端发送用户上线的消息
                chatEndPoint chatEndPoint = onlineUsers.get(name);
                chatEndPoint.session.getBasicRemote().sendText(message);
            }
               return onlineFriends;
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    //发送消息给客户端，显示当前用户的在线好友
    public void displayOnlineFriends(List<String> onlineFriends,String curUserName) throws IOException
    {
        System.out.println("==========================");
        System.out.println("发送消息给客户端，显示当前用户的在线好友");
        chatEndPoint chatEndPoint = onlineUsers.get(curUserName);
        //调用sendText方法向A用户发送第一条消息还未结束，
        //继续调用sendText方法向A用户发送第二条消息的情况。
        //此时就会报错java.lang.IllegalStateException: The remote endpoint was in state。
        //使用synchronized()锁住此session，使此session在调用结束时再进行第二次调用
        synchronized(session){
            session.getBasicRemote().sendText(objectMapper.writeValueAsString(onlineFriends));
        }
    }

    @OnMessage//接收到客户端发送的数据时被调用
    public void OnMessage(String message,Session session) throws IOException {
        System.out.println("==============================");
        System.out.println("客户端发送的数据为:  "+message);
        //将msg转换成Message对象
        //readValue将json字符串转换为指定对象
        Message msg = objectMapper.readValue(message, Message.class);
        //获取要将数据发送给谁
        String toName = msg.getToName();
        //获取消息数据
        String data = msg.getMessage();
        //获取当前登录的用户
        //获取推送给指定用户的消息格式的数据
        String resMsg = MessageUtils.getMessage(false, uname, data);
        //发送数据
        onlineUsers.get(toName).session.getBasicRemote().sendText(resMsg);
    }

    @OnClose//链接关闭时被调用
    public void OnClose(Session session)
    {
        //用户下线
        onlineNum--;
        System.out.println("================");
        System.out.println("当前用户"+uname+"下线");
        //用户断开连接后，从当前在线用户列表中移除
           onlineUsers.remove(uname);
    }

    @OnError//出现异常
    public void onError(Session session,Throwable throwable)
    {

        System.out.println("当前用户:"+uname+"连接出现异常");
        //用户断开连接后，从当前在线用户列表中移除
        onlineUsers.remove(uname);
    }
}
